<template>
  <view class="camera">
    <!-- 相机组件 -->
    <view v-show="isShow">
      <camera
        v-if="isAuth"
        :device-position="devPosition ? 'front' : 'back'"
        flash="off"
        @error="error"
      />
      <view class="footer">
        <view class="back" v-if="back">
          <view @tap="Back">
            <image :src="require('../Camera/IconFont/back.png')" mode="aspectFill" />
          </view>
        </view>
        <view class="album" v-else>
          <view @tap="Album">
            <image :src="require('../Camera/IconFont/album.png')" mode="aspectFill" />
          </view>
        </view>
        <view class="takePhoto">
          <view @tap="TakePhoto">
            <image :src="require('../Camera/IconFont/takePhoto.png')" mode="aspectFill" />
          </view>
        </view>
        <view class="devPosition">
          <view @tap="CameraPosition">
            <image :src="require('../Camera/IconFont/devPosition.png')" mode="aspectFill" />
          </view>
        </view>
      </view>
    </view>
    <!-- 裁剪 -->
    <CroppingImg ref="croppingRef" v-if="isCrop" @close="closeCrop" />
    <!-- 预览 -->
    <PreViewImg v-else ref="previewRef" />
  </view>
</template>
<script>
import PreViewImg from './Preview/index.vue'
import CroppingImg from './Cropping/index.vue'
export default {
  components: {
    PreViewImg,
    CroppingImg,
  },
  data() {
    return {
      isAuth: false, //用户是否授权调用相机权限
      isShow: true,
      devFront: '',
    }
  },
  props: {
    /**
     * 是否开启裁剪(使用裁剪功能将会禁用照片仅预览功能)
     * @param {default:false}
     */
    isCrop: {
      type: Boolean,
      default: false,
    },
    /**
     * 前后置摄像头状态
     * 默认前置状态
     * @param {default:true}
     */
    devPosition: {
      type: Boolean,
      default: true,
    },
    /**
     * 是否开启返回（开启返回按钮，选择相册功能将禁用，仅可拍照）
     * @param {default:false}
     */
    back: {
      type: Boolean,
      default: false,
    },
    /**
     * 图片预览临时路径
     * @param {default:""}
     */
    tempImagePath: {
      type: String,
      default: '',
    },
  },
  watch: {
    // 监听前后置镜头转换状态变化
    devPosition: {
      deep: true,
      immediate: true,
      handler(newValue, oldValue) {
        return newValue
      },
    },
  },
  methods: {
    /**
     * 打开相机回调函数方法
     * @param {Boolean} isAuth
     */
    open() {
      const that = this
      uni.getSetting({
        success: (res) => {
          if (res.authSetting['scope.camera']) {
            // 用户已经授权
            that.isAuth = true
          } else {
            // 用户还没有授权，向用户发起授权请求
            uni.authorize({
              scope: 'scope.camera',
              success() {
                // 用户同意授权
                that.isAuth = true
              },
              fail() {
                // 用户不同意授权
                that.OpenSetting().then((res) => {
                  that.isAuth = true
                })
              },
            })
          }
        },
        fail: (res) => {
          uni.$u.toast('获取用户授权信息失败' + res)
        },
      })
    },
    /**
     * 打开授权设置界面
     * @param {type}  = [value]
     */
    OpenSetting() {
      const that = this
      let promise = new Promise((resolve, reject) => {
        uni.showModal({
          title: '授权',
          content: '请先授权获取摄像头权限',
          success(res) {
            if (res.confirm) {
              uni.openSetting({
                success(res) {
                  if (res.authSetting['scope.camera']) {
                    // 用户打开了授权开关
                    resolve(true)
                  } else {
                    // 用户没有打开授权开关， 继续打开设置页面
                    that.OpenSetting().then((res) => {
                      resolve(true)
                    })
                  }
                },
                fail(res) {
                  uni.$u.toast('错误代码:' + res)
                },
              })
            } else if (res.cancel) {
              that.OpenSetting().then((res) => {
                resolve(true)
              })
            }
          },
        })
      })
      return promise
    },
    /**
     * 返回回调函数方法
     * @param {$emit} Back
     */
    Back() {
      const that = this
      that.$emit('Back')
    },
    /**
     * 选择相册照片回调函数方法
     * @param {String} tempFilePaths[0]
     */
    async Album() {
      const that = this
      uni.chooseImage({
        sourceType: ['album'],
        success(res) {
          if (res.errMsg == 'chooseImage:ok') {
            that.setMode(res.tempFilePaths[0])
          }
        },
        fail(res) {
          uni.$u.toast('错误代码:' + res)
        },
      })
    },
    /**
     * 拍照回调函数方法
     * @param {String} tempImagePath
     */
    TakePhoto() {
      const that = this
      const ctx = uni.createCameraContext()
      ctx.takePhoto({
        quality: 'high',
        success: (res) => {
          that.setMode(res.tempImagePath)
        },
      })
    },
    /**
     * 判断是否使用裁剪或仅预览模式
     * @param {Object} data
     */
    setMode(data) {
      if (this.isCrop) {
        this.$refs.croppingRef.open(data) //裁剪
        this.isShow = false
      } else {
        this.$refs.previewRef.open(data) //仅预览
      }
    },
    /**
     * 切换前后置摄像头回调函数方法
     * @param {$emit} CameraPosition
     */
    CameraPosition() {
      this.$emit('CameraPosition')
    },
    /**
     * 关闭照片裁剪功能回调函数方法
     * @param {Boolean} isShow
     */
    closeCrop() {
      this.isShow = true
    },
  },
}
</script>
<style lang="scss" scoped>
.camera {
  position: relative;
  width: 100%;
  height: 100%;
}

.camera camera {
  height: 100vh;
}

.footer {
  position: fixed;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  padding-top: 20rpx;
  padding-bottom: 30rpx;
  background: #fff;
  border-radius: 10rpx 10rpx 0 0;
  box-shadow: 0 0 15rpx rgba(244, 244, 244, 0.4);

  .back,
  .album,
  .takePhoto,
  .devPosition {
    margin: auto;

    image {
      width: 75rpx;
      height: 75rpx;
    }
  }

  .album {
    image {
      width: 85rpx;
      height: 85rpx;
    }
  }

  .takePhoto {
    image {
      width: 120rpx;
      height: 120rpx;
    }
  }
}
</style>
